/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import org.aswing.ASColor;
import org.aswing.border.EmptyBorder;
import org.aswing.BorderLayout;
import org.aswing.Component;
import org.aswing.Container;
import org.aswing.Insets;
import org.aswing.JLabel;
import org.aswing.JPanel;
import org.aswing.UIManager;

import com.bourre.commands.Delegate;

import fever.data.validators.ValidationResources;
import fever.exception.IllegalAccessException;
import fever.exception.IllegalArgumentException;
import fever.utils.Stringifier;

import fvaswing.components.FvForm;

/**
 * Abstract implementation for {@link fvaswing.components.FvForm} fields.
 * 
 * <p>New fields can be implemented using this abstract class.
 * <ul>
 *   <li>override {@link #setValue()} method</li>
 *   <li>override {@link #getValue()} method</li>
 *   <li>override {@link #clear()} method</li>
 *   <li>override {@code _createValueComponent()} method</li>
 *   <li>override {@code _validateField()} method</li>
 * </ul>
 * 
 * <p>Take a look at <strong>fvaswing.components.forms</strong> package to see 
 * concrete field implementations.
 * 
 * @see fvaswing.components.FvForm
 * 
 * @author Romain Ecarnot
 */
class fvaswing.components.forms.FvFormField
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private var _caption : String;
	private var _label : JLabel;
	private var _preventLabel : JLabel;
	private var _lineLabel : JPanel;
	private var _container : JPanel;
	private var _isValidationEnabled : Boolean;	private var _errorMsg : String;
	
	private var _pendingCall : Boolean;
	private var _pendingData;
	
	private var _dStateRender : Delegate;
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Inits fields
	 * 
	 * <p>Don't use it in our development<br />
	 * triggered when field is added to form component.
	 */
	public function init( w : Number,  scopeMethod, renderingMethod : Function ) : Void
	{
		_lineLabel.setPreferredWidth( w + 25 ); //adds 25 px for possible icon
		setRenderStateHandler( scopeMethod, renderingMethod );
		
		showValidState();
	}
	
	/**
	 * Delegates field state rendering method to passed-in {@code renderingMethod} function.
	 * 
	 * @param scopeMethod Context where function is call.
	 * @param renderingMethod Function implementation to render field state
	 */
	public function setRenderStateHandler( scopeMethod, renderingMethod : Function ) : Void
	{
		if( scopeMethod && renderingMethod )
			 _dStateRender = new Delegate( scopeMethod, renderingMethod );
	}
	
	public function setCaption( str : String ) : Void
	{
		if( str != _caption )
		{
			_caption = str;
			_label.setText( _caption );
			_label.revalidateIfNecessary();
		}	
	}
	
	/**
	 * Returns field's label.
	 */
	public function getCaption() : String
	{
		return _caption;
	}
	
	/**
	 * Returns <strong>AsWing</strong> field container.
	 */
	public function getContainer() : Container
	{
		if( !_container )
		{
			_lineLabel = new JPanel( new BorderLayout( 5,5 ) );
			_lineLabel.append( _createLabelComponent(), BorderLayout.WEST );
			_lineLabel.append( _createPreventLabelComponent(), BorderLayout.EAST );
			
			_container = new JPanel( new BorderLayout( 5, 5 ) );
			_container.append( _lineLabel, BorderLayout.WEST );
			_container.append( _createValueComponent(), BorderLayout.CENTER );
			_container.addEventListener( JPanel.ON_CREATED, _initField, this );
		}
		
		return _container;
	}
	
	/**
	 * Returns current label width.
	 */
	public function getLabelWidth() : Number
	{
		return _label.getPreferredWidth();
	}
	
	/**
	 * Sets field value.<br />
	 * Must be override by subclass.
	 */
	public function setValue( value ) : Void
	{
		if( _pendingCall ) _pendingData = value;
		else _initWithData( value );
	}
	
	/**
	 * Returns field value.<br />
	 * Must be override by subclass.
	 */
	public function getValue( )
	{
		throw new IllegalAccessException( '.getValue() must be override in field subclass' );
		return null;
	}
	
	/**
	 * Returns {@code true} is current field is valid.
	 * 
	 * <p>Validation process is defined throw class instanciation<br />
	 * Take a look at constructor definition.
	 */
	public function isFieldValid() : Boolean
	{
		if( !_isValidationEnabled ) return true;
		else return _validateField();	
	}
	
	/**
	 * Shows visual indication for a valid field state.
	 * 
	 * <p>Usually the 'normal' state of field.
	 */
	public function showValidState() : Void
	{
		_dStateRender.setArguments( 
			_label, 
			_caption, 
			_preventLabel,
			_isValidationEnabled, 
			true, 
			ValidationResources.getInstance().required_field_error 
		);		_dStateRender.execute();
	}
	
	/**
	 * Shows visual indication for an invalid field state.
	 * 
	 * <p>Default use a red background for target component.
	 */
	public function showInvalidState() : Void
	{
		_dStateRender.setArguments( 
			_label, 
			_caption,
			_preventLabel, 
			_isValidationEnabled, 
			false, 
			_errorMsg 
		);
		_dStateRender.execute();
	}
	
	/**
	 * Reset field to default value.<br />
	 * Must be override by subclass.
	 */
	public function clear() : Void
	{
		throw new IllegalAccessException( '.clear() must be override in field subclass' );	
	}
	
	/**
	 * Returns string representation.
	 */
	public function toString() : String
	{
		return Stringifier.parse( this );
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	/**
	 * Constructor.
	 */
	private function FvFormField( label : String )
	{
		if( label )
		{
			_caption = label;
			_isValidationEnabled = false;
			_dStateRender = new Delegate( this, _renderValidationState );
			_pendingCall = true;
		}
		else throw new IllegalArgumentException( 'Forms\' label can\' be null or undefined' ); 	
	}
	
	/**
	 * Returns component dedicated to field caption.
	 */
	private function _createLabelComponent() : Component
	{
		_label = new JLabel( _caption, JLabel.LEFT );		_label.setVerticalAlignment( JLabel.TOP );
				
		return _label;
	}
	
	/**
	 * Returns component dedicated to field caption.
	 */
	private function _createPreventLabelComponent() : Component
	{
		_preventLabel = new JLabel( );
		_preventLabel.setVerticalAlignment( JLabel.TOP );
		_preventLabel.setHorizontalAlignment( JLabel.RIGHT );
		_preventLabel.setBorder( new EmptyBorder( null, new Insets( 0, 0, 0, 5 ) ) );
		return _preventLabel;
	}
	
	/**
	 * Returns component dedicated to field value.<br />
	 * Must be override by subclass.
	 */
	private function _createValueComponent() : Component
	{
		throw new IllegalAccessException( '._createValueComponent() must be override in field subclass' );
		return null;
	}
	
	/**
	 * Process validation.<br />
	 * Must be override by subclass.
	 */
	private function _validateField() : Boolean
	{
		throw new IllegalAccessException( '._validateField() must be override in field subclass' );
		return null;
	}
	
	private function _triggerResult( b : Boolean, msg : String ) : Boolean
	{
		if( b )
		{
			showValidState();			
			return true;
		}
		else
		{
			_errorMsg = msg;
			showInvalidState();
			
			return false;
		}	
	}
	
	private function _initWithData( value ) : Void
	{
		throw new IllegalAccessException( '._initWithData() must be override in sub class' );
	}
	
	private function _initField( source : JPanel ) : Void
	{
		if( _pendingCall ) _initWithData( _pendingData );
		
		_pendingCall = false;
	}
	
	private function _renderValidationState( captionLabel : JLabel, caption : String, preventLabel : JLabel, must : Boolean, valid : Boolean, msg : String ) : Void
	{
		if( valid )
		{
			captionLabel.setForeground( UIManager.getColor( 'TextField.foreground' ) );
			
			if( must )
			{
				preventLabel.setText( FvForm.REQUIRED_FIELD_SUFFIX );
				preventLabel.setToolTipText( msg );				captionLabel.setToolTipText( msg );			}
			else
			{
				preventLabel.setText();				preventLabel.setToolTipText();
			}
		}
		else
		{
			captionLabel.setForeground( ASColor.RED );
			captionLabel.setToolTipText( msg );				preventLabel.setToolTipText( msg );			}
	}
}